﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ViCode_LeVi.Data;

namespace ViCode_LeVi.Controls
{
    /// <summary>
    /// Interaction logic for VMTabBudgetChart.xaml
    /// </summary>
    public partial class VMTabBudgetChart : UserControl
    {
        public VMTabBudgetChart()
        {
            InitializeComponent();
            Setup_Ellipse_Main();
            this.MouseWheel -= new MouseWheelEventHandler(UserControl_Scroll_Font_MouseWheel);
            this.MouseWheel += new MouseWheelEventHandler(UserControl_Scroll_Font_MouseWheel);
        }


        void UserControl_Scroll_Font_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            bool handle = (Keyboard.Modifiers & ModifierKeys.Control) > 0;
            if (!handle)
                return;

            Zoom(e);
            e.Handled = true;
        }
        private void Zoom(MouseWheelEventArgs e)
        {
            //if (Application.Current.Resources.Contains("FES_MainFontSize"))
            //{
            //    double font = (double)Application.Current.Resources["FES_MainFontSize"];
            //    double inc = e.Delta / 75;
            //    double newFont = font + inc;
            //    if (newFont >= 5 && newFont < 50)
            //    {
            //        Application.Current.Resources["FES_MainFontSize"] = newFont;
            //    }
            //}            
            var negative = e.Delta < 0;
            var lDelta = Math.Abs(e.Delta);
            var rate = negative == false ? 1.2 : 0.8;
            if (rate > 0)
            {                
                var newWidth = canvas.ActualWidth * rate;
                if (newWidth > 50)
                {
                    var newHeight = canvas.ActualHeight * rate;
                    canvas.Width = newWidth;
                    canvas.Height = newHeight;
                }
            }


        }

        #region Setup_Ellipse_Main
        private void Setup_Ellipse_Main()
        {
            Setup_Ellipse_Main_Run();
            canvas.SizeChanged -= new SizeChangedEventHandler(canvas_SizeChanged);
            canvas.SizeChanged += new SizeChangedEventHandler(canvas_SizeChanged);
            Ellipse_Main.MouseEnter += new MouseEventHandler(Ellipse_Main_MouseEnter);
            Ellipse_Main.MouseLeave += new MouseEventHandler(Ellipse_Main_MouseLeave);
        }

        void Ellipse_Main_MouseLeave(object sender, MouseEventArgs e)
        {
            Ellipse_Main.Stroke = Brushes.Black;
        }

        void Ellipse_Main_MouseEnter(object sender, MouseEventArgs e)
        {
            Ellipse_Main.Stroke = Brushes.Red;
        }

        void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Setup_Ellipse_Main_Run();
        }

        private void Setup_Ellipse_Main_Run()
        {
            var minWH = canvas.ActualWidth;
            if (minWH > canvas.ActualHeight)
                minWH = canvas.ActualHeight;
            Ellipse_Main.Width = minWH;
            Ellipse_Main.Height = minWH;
            Canvas.SetTop(Ellipse_Main, (canvas.ActualHeight - minWH) / 2.0);
            Canvas.SetLeft(Ellipse_Main, (canvas.ActualWidth - minWH) / 2.0);
        }
        #endregion

        public void DrawChart()
        {
            //remove all
            var uiChilds = canvas.Children.Cast<UIElement>().Where(c => c != Ellipse_Main).ToArray(); ;
            foreach (var ui in uiChilds)
            {
                canvas.Children.Remove(ui);
                ui.MouseWheel -= new MouseWheelEventHandler(UserControl_Scroll_Font_MouseWheel);
            }

            //Draw
            Step_Budget Budget = this.DataContext as Step_Budget;
            Ellipse_Main.DataContext = Budget;
            Ellipse_Main.ToolTip = BudgetChartHelper.CreateTooltip(Budget);
            Ellipse_Main.MouseWheel -= new MouseWheelEventHandler(UserControl_Scroll_Font_MouseWheel);
            Ellipse_Main.MouseWheel += new MouseWheelEventHandler(UserControl_Scroll_Font_MouseWheel);

            BudgetChartHelper.Rate = Ellipse_Main.ActualWidth / 100;
            DrawChartChild(Budget);
        }
        public void DrawChartChild(Step_Budget Budget)
        {
            if (Budget != null)
            {
                BudgetChartHelper.Action_EllipseCreated = (ell) =>
                    {
                        ell.MouseWheel -= new MouseWheelEventHandler(UserControl_Scroll_Font_MouseWheel);
                        ell.MouseWheel += new MouseWheelEventHandler(UserControl_Scroll_Font_MouseWheel);
                    };
                BudgetChartHelper.CreateCircleChild(canvas, Ellipse_Main, Budget.Childs.ToArray());
            }
        }
    }
    public static class BudgetChartHelper
    {
        public static Action<Ellipse> Action_EllipseCreated;
        public static double Rate = 1;
        static double changeBanKinh(Ellipse parent, Step_Budget firstChildDK)
        {
            double value = firstChildDK.CostCurrent;
            double valueParent = firstChildDK.Parent == null ? firstChildDK.CostCurrent : firstChildDK.Parent.CostCurrent;
            double valueReturn = value;
            double rate = 1;
            if (value < valueParent / 2)
            {
                //=2 thi phai chua doi duong kinh roi
                if (firstChildDK.Parent != null && firstChildDK.Parent.Childs.Count > 2)
                {
                    //var temp = valueParent / 2 - value;
                    //rate = Math.Sqrt((firstChildDK.Parent.Childs.Count - 2));
                }
            }
            if (rate == 0)
                rate = 1;
            //return (bankinh + Math.Sqrt(temp)) * Rate;
            var parentWidth = parent.Width > 0 ? parent.Width : parent.ActualWidth;
            valueReturn = rate * (valueReturn) * parentWidth / valueParent;
            return valueReturn / 2;
        }
        public static StackPanel CreateTooltip(Step_Budget data)
        {
            StackPanel ttStack = new StackPanel();
            if (data != null)
            {
                var txtName = new TextBlock() { Margin = new Thickness(2) };
                txtName.SetBinding(TextBlock.TextProperty, new Binding("Name"));
                var txtCost = new TextBlock() { Margin = new Thickness(2) };
                txtCost.SetBinding(TextBlock.TextProperty, new Binding("CostCurrent"));
                ttStack.Children.Add(txtName);
                ttStack.Children.Add(txtCost);
            }
            return ttStack;
        }
        public static Ellipse CreateEllipse()
        {
            var ellipse = new Ellipse();
            if (Action_EllipseCreated != null)
                Action_EllipseCreated(ellipse);
            return ellipse;
        }
        public static Ellipse CreateCircle(Ellipse parent, Step_Budget data)
        {
            var bankinh = changeBanKinh(parent, data);
            var ellipse = CreateEllipse();
            ellipse.Stroke = Brushes.Black;
            ellipse.StrokeThickness = 1;
            ellipse.Fill = new SolidColorBrush(Colors.Azure);
            ellipse.Width = bankinh * 2;
            ellipse.Height = bankinh * 2;
            //tooltip            
            ellipse.DataContext = data;
            ellipse.ToolTip = CreateTooltip(data);

            ellipse.MouseEnter -= new MouseEventHandler(Ellipse_Main_MouseEnter);
            ellipse.MouseEnter += new MouseEventHandler(Ellipse_Main_MouseEnter);
            ellipse.MouseLeave -= new MouseEventHandler(Ellipse_Main_MouseLeave);
            ellipse.MouseLeave += new MouseEventHandler(Ellipse_Main_MouseLeave);
            return ellipse;

        }

        static void Ellipse_Main_MouseLeave(object sender, MouseEventArgs e)
        {
            Ellipse elp = sender as Ellipse;
            if (elp != null)
            {
                elp.Stroke = Brushes.Black;
            }
        }

        static void Ellipse_Main_MouseEnter(object sender, MouseEventArgs e)
        {
            Ellipse elp = sender as Ellipse;
            if (elp != null)
            {
                elp.Stroke = Brushes.Red;
            }
        }
        public static void CreateCircleChild(Canvas canvasCtrl, Ellipse parent, Step_Budget[] childDKs)
        {
            childDKs = childDKs.OrderByDescending(c => c.CostCurrent).ToArray();
            Ellipse biggestBrother = null;
            if (childDKs.Length > 0)
            {
                var firstChild = childDKs[0];
                biggestBrother = CreateCircleFirstChild(canvasCtrl, parent, firstChild);
                //de quy
                if (firstChild.Childs != null && firstChild.Childs.Count > 0)
                    CreateCircleChild(canvasCtrl, biggestBrother, firstChild.Childs.ToArray());
            }
            //others
            var OthersChild = childDKs.Skip(1).ToArray();
            List<Ellipse> listOthers = new List<Ellipse>();
            for (int i = 0; i < OthersChild.Length; i++)
            {
                var newEllipse = CreateCircleChild(canvasCtrl, parent, biggestBrother, listOthers, OthersChild[i]);
                listOthers.Add(newEllipse);
                //de quy
                if (OthersChild[i].Childs != null && OthersChild[i].Childs.Count > 0)
                    CreateCircleChild(canvasCtrl, newEllipse, OthersChild[i].Childs.ToArray());

            }
        }

        public static Ellipse CreateCircleFirstChild(Canvas canvasCtrl, Ellipse parent, Step_Budget firstChildDK)
        {
            var ellipse = CreateCircle(parent, firstChildDK);
            var bankinh = ellipse.Width / 2.0;
            var pCenterParent = TimTamVongTron(parent);
            var pcenter = new Point();
            pcenter.Y = pCenterParent.Y;
            var parentWidth = parent.Width > 0 ? parent.Width : parent.ActualWidth;
            pcenter.X = pCenterParent.X - ((parentWidth / 2.0) - bankinh); ;

            var pLeftTop = BudgetChartHelper.TimLopLeftTuTamVaBanKinh(pcenter, bankinh);
            ellipse.SetValue(Canvas.LeftProperty, (double)pLeftTop.X); //set x
            ellipse.SetValue(Canvas.TopProperty, (double)pLeftTop.Y); //set y

            canvasCtrl.Children.Add(ellipse);
            return ellipse;
        }
        public static Ellipse CreateCircleChild(Canvas canvasCtrl, Ellipse parent, Ellipse biggestBrother, List<Ellipse> OtherBrothers, Step_Budget childDK)
        {
            var ellipse = CreateCircle(parent, childDK);
            var bankinh = ellipse.Width / 2.0;
            canvasCtrl.Children.Add(ellipse);
            var pcenter4 = BudgetChartHelper.TimTamVongTronTXNvaOTrong(biggestBrother, parent, bankinh, OtherBrothers);//
            var pLeftTop4 = BudgetChartHelper.TimLopLeftTuTamVaBanKinh(pcenter4, bankinh);
            ellipse.SetValue(Canvas.LeftProperty, (double)pLeftTop4.X); //set x
            ellipse.SetValue(Canvas.TopProperty, (double)pLeftTop4.Y); //set y
            return ellipse;
        }

        #region Math
        public static bool IsChuaTrongHoacTiepXucTrong(Ellipse _ellipe1, Ellipse _ellipe2)
        {
            var pCenter1 = TimTamVongTron(_ellipe1);
            var pCenter2 = TimTamVongTron(_ellipe2);
            double chieuDai = GetDistanceBetweenPoints(pCenter1, pCenter2);
            double triTuyetDoiBanKinh = Math.Abs((_ellipe1.Width / 2d) - (_ellipe2.Width / 2d));
            if (chieuDai <= triTuyetDoiBanKinh)
                return true;
            return false;
        }
        public static bool IsChuaTrong(Ellipse _ellipe1, Ellipse _ellipe2)
        {
            var pCenter1 = TimTamVongTron(_ellipe1);
            var pCenter2 = TimTamVongTron(_ellipe2);
            double chieuDai = GetDistanceBetweenPoints(pCenter1, pCenter2);
            double triTuyetDoiBanKinh = Math.Abs((_ellipe1.Width / 2d) - (_ellipe2.Width / 2d));
            if (chieuDai < triTuyetDoiBanKinh)
                return true;
            return false;
        }
        public static bool IsChuaTrong(Ellipse _ellipe1, Point pCenter2, double bankinh2)
        {
            var pCenter1 = TimTamVongTron(_ellipe1);

            double chieuDai = GetDistanceBetweenPoints(pCenter1, pCenter2);
            double triTuyetDoiBanKinh = Math.Abs((_ellipe1.Width / 2d) - bankinh2);
            if (chieuDai < triTuyetDoiBanKinh)
                return true;
            return false;
        }
        public static bool IsLongNhau(Ellipse _ellipe1, Point pCenter2, double bankinh2)
        {
            var pCenter1 = TimTamVongTron(_ellipe1);

            double chieuDai = GetDistanceBetweenPoints(pCenter1, pCenter2);
            double triTuyetDoiBanKinh = Math.Abs((_ellipe1.Width / 2d) - bankinh2);
            double tong2BK = (_ellipe1.Width / 2d) + bankinh2;
            if (chieuDai > triTuyetDoiBanKinh
                && chieuDai < tong2BK)
                return true;
            return false;
        }
        public static bool IsNamTrongHoacTiepXucTrong(Point pCenter1, Point pCenter2, double bankinh1, double bankinh2)
        {
            double chieuDai = GetDistanceBetweenPoints(pCenter1, pCenter2);
            double triTuyetDoiBanKinh = Math.Abs(bankinh1 - bankinh2);
            if (LessThan(chieuDai, triTuyetDoiBanKinh))
                return true;
            return false;
        }
        public static bool IsTiepXucNgoai(Ellipse _ellipe1, Ellipse _ellipe2)
        {
            var pCenter1 = TimTamVongTron(_ellipe1);
            var pCenter2 = TimTamVongTron(_ellipe2);
            double chieuDai = GetDistanceBetweenPoints(pCenter1, pCenter2);
            double tongBanKinh = (_ellipe1.Width / 2d) + (_ellipe2.Width / 2d);
            if (chieuDai == tongBanKinh)
                return true;
            return false;
        }
        public static double Delta = 1;
        public static bool IsEqual(this double a, double b)
        {
            return Math.Abs(a - b) <= Delta;
        }
        public static bool LessThan(this double a, double b)
        {
            if (a < b)
                return true;
            else
            {
                if (a - Delta < b)
                    return true;
            }
            return false;
        }
        public static bool IsTiepXucNgoai(Point pCenter1, Point pCenter2, double bankinh1, double bankinh2)
        {
            double chieuDai = GetDistanceBetweenPoints(pCenter1, pCenter2);
            double tongBanKinh = bankinh2 + bankinh1;
            if (IsEqual(chieuDai, tongBanKinh))
                return true;
            return false;
        }
        public static double GetDistanceBetweenPoints(Point p, Point q)
        {
            double a = p.X - q.X;
            double b = p.Y - q.Y;
            double distance = Math.Sqrt(a * a + b * b);
            return distance;
        }
        static int radianStart = 90;
        public static Point TimTamVongTron(Ellipse _ellipe)
        {
            double _ellipe_top = Canvas.GetTop(_ellipe);
            double _ellipe_left = Canvas.GetLeft(_ellipe);
            double _ellipe_center_y = _ellipe_top + _ellipe.Height / 2;
            double _ellipe_center_x = _ellipe_left + _ellipe.Width / 2;
            return new Point(_ellipe_center_x, _ellipe_center_y);
        }
        /// <summary>
        /// Tim vong trong co ban kinh bang ban kinh cua _ellipe + bankinh
        /// tam : la tam cua _ellipe
        /// </summary>
        /// <param name="_ellipe"></param>
        /// <param name="bankinh"></param>
        /// <returns></returns>        
        public static Point[] TimCacDiemTrenVongTronLon(Ellipse _ellipe, double bankinh)
        {
            Point pCenter = TimTamVongTron(_ellipe);
            double bankinhLon = bankinh + _ellipe.Height / 2;
            List<Point> listPoints = new List<Point>();
            for (double anpha = 360; anpha > 0; anpha = anpha - 0.1)
            {
                var anphanSub = (anpha - 360 + radianStart) % 360;
                double x = pCenter.X + bankinhLon * (Math.Cos(anphanSub * Math.PI / 180d));
                double y = pCenter.Y + bankinhLon * (Math.Sin(anphanSub * Math.PI / 180d));
                listPoints.Add(new Point(x, y));
            }
            return listPoints.ToArray();
        }

        public static Point TimTamVongTronTXNvaOTrong(Ellipse _ellipseTXN, Ellipse _ellipseTXT, double bankinh)
        {
            double banKinhTXN = _ellipseTXN.Width / 2d;
            double banKinhTXT = _ellipseTXT.Width / 2d;
            Point pcenterTXN = TimTamVongTron(_ellipseTXN);
            Point pcenterTXT = TimTamVongTron(_ellipseTXT);
            Point pCenter = new Point();
            var listPoint = TimCacDiemTrenVongTronLon(_ellipseTXN, bankinh);
            foreach (var _point in listPoint)
            {

                bool isTiepXucNgoai = IsTiepXucNgoai(pcenterTXN, _point, banKinhTXN, bankinh);
                bool isTiepXucTrong = IsNamTrongHoacTiepXucTrong(pcenterTXT, _point, banKinhTXT, bankinh);
                if (isTiepXucNgoai && isTiepXucTrong)
                    return _point;
            }
            return pCenter;
        }

        public static bool IsCatCacEllipesKhac(List<Ellipse> _ellipsSub, Point point, double bankinh)
        {
            foreach (var ellip in _ellipsSub)
            {

                if (IsChuaTrong(ellip, point, bankinh)
                    ||
                    IsLongNhau(ellip, point, bankinh))
                    return true;
            }
            return false;
        }
        public static Point TimTamVongTronTXNvaOTrong(Ellipse _ellipseTXN, Ellipse _ellipseTXT, double bankinh, List<Ellipse> _ellipsSub)
        {
            double banKinhTXN = _ellipseTXN.Width / 2d;
            double banKinhTXT = _ellipseTXT.Width / 2d;
            Point pcenterTXN = TimTamVongTron(_ellipseTXN);
            Point pcenterTXT = TimTamVongTron(_ellipseTXT);
            Point pCenter = new Point();
            var listPoint = TimCacDiemTrenVongTronLon(_ellipseTXN, bankinh);
            for (int i = 0; i < 5; i++)
            {
                Delta = i;
                foreach (var _point in listPoint)
                {
                    bool isTiepXucNgoai = IsTiepXucNgoai(pcenterTXN, _point, banKinhTXN, bankinh);
                    bool isTiepXucTrong = IsNamTrongHoacTiepXucTrong(pcenterTXT, _point, banKinhTXT, bankinh);
                    bool isCatEllipKhac = IsCatCacEllipesKhac(_ellipsSub, _point, bankinh);
                    if (isTiepXucNgoai && isTiepXucTrong && !isCatEllipKhac)
                        return _point;
                }
                if (pCenter.X == 0 && pCenter.Y == 0)
                {
                    continue;
                }
                else
                {
                    break;
                }
            }
            return pCenter;
        }
        public static Point TimLopLeftTuTamVaBanKinh(Point pCenter, double bankinh)
        {
            double x = pCenter.X - bankinh;
            double y = pCenter.Y - bankinh;
            return new Point(x, y);
        }
        #endregion
    }
}
